﻿using Cinch;
using FR.SAFTAnalyser.Model;
using MEFedMVVM.Common;
using OfficeOpenXml;
using OfficeOpenXml.Table;
using OfficeOpenXml.Table.PivotTable;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FR.SAFTAnalyser.ViewModels
{
    public class InvoicesSummaryViewModel : WorkspaceViewModel
    {
        public InvoicesSummaryViewModel()
        {
            if (!Designer.IsInDesignMode)
            {
                Mediator.Instance.Register(this);
                this.DisplayName = "Resumo";

                DoExportDocumentsCommand = new SimpleCommand<object, object>(CanExportDocuments, ExportDocuments);
                DoExportlinesCommand = new SimpleCommand<object, object>(CanExportLines, ExportLines);
            }
        }

        SourceDocumentsSalesInvoicesInvoiceLine[] allLines;
        SourceDocumentsSalesInvoicesInvoice[] allInvoices;

        #region Mediator messages
        [MediatorMessageSink(MessageType.SAFT_FILE_OPENED)]
        private void LoadInvoices(AuditFile saft)
        {
            if (saft != null && saft.SourceDocuments != null && saft.SourceDocuments.SalesInvoices != null && saft.SourceDocuments.SalesInvoices.Invoice != null && saft.SourceDocuments.SalesInvoices.Invoice.Length > 0)
            {
                HasDocuments = true;
                allLines = saft.SourceDocuments.SalesInvoices.Invoice.SelectMany(i => i.Line).ToArray();
                allInvoices = saft.SourceDocuments.SalesInvoices.Invoice;

                TotalDebit = saft.SourceDocuments.SalesInvoices.TotalDebit;
                TotalCredit = saft.SourceDocuments.SalesInvoices.TotalCredit;
            }

            AgruparDocumentosDia = true;
            AgruparLinhasPorCodigo = true;
        }
        #endregion Mediator messages

        #region Binding properties
        bool hasDocuments;
        public bool HasDocuments
        {
            get { return hasDocuments; }
            set
            {
                hasDocuments = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.HasDocuments));
            }
        }

        bool processingData;
        public bool ProcessingData
        {
            get { return processingData; }
            set
            {
                processingData = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.ProcessingData));
            }
        }

        decimal totalDebit;
        public decimal TotalDebit
        {
            get { return totalDebit; }
            set
            {
                totalDebit = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.TotalDebit));
            }
        }

        decimal totalCredit;
        public decimal TotalCredit
        {
            get { return totalCredit; }
            set
            {
                totalCredit = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.TotalCredit));
            }
        }

        LinhasAgrupadas[] invoiceLines;
        public LinhasAgrupadas[] InvoiceLines
        {
            get { return invoiceLines; }
            set
            {
                invoiceLines = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.InvoiceLines));
            }
        }

        bool agruparLinhasPorCodigo;
        public bool AgruparLinhasPorCodigo
        {
            get { return agruparLinhasPorCodigo; }
            set
            {
                agruparLinhasPorCodigo = value;

                if (agruparLinhasPorCodigo)
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.DoWork += bw_DoWorkGroupLinesCode;
                    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
                    bw.RunWorkerAsync();
                }

                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.AgruparLinhasPorCodigo));
            }
        }

        bool agruparLinhasPorDescricao;
        public bool AgruparLinhasPorDescricao
        {
            get { return agruparLinhasPorDescricao; }
            set
            {
                agruparLinhasPorDescricao = value;

                if (agruparLinhasPorDescricao)
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.DoWork += bw_DoWorkGroupLinesDescription;
                    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
                    bw.RunWorkerAsync();
                }

                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.AgruparLinhasPorDescricao));
            }
        }

        DocumentosAgrupados[] invoices;
        public DocumentosAgrupados[] Invoices
        {
            get { return invoices; }
            set
            {
                invoices = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.Invoices));
            }
        }

        bool agruparDocumentosMes;
        public bool AgruparDocumentosMes
        {
            get { return agruparDocumentosMes; }
            set
            {
                agruparDocumentosMes = value;

                if (agruparDocumentosMes)
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.DoWork += bw_DoWorkGroupDocumentsMonth;
                    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
                    bw.RunWorkerAsync();
                }

                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.AgruparDocumentosMes));
            }
        }

        bool agruparDocumentosDia;
        public bool AgruparDocumentosDia
        {
            get { return agruparDocumentosDia; }
            set
            {
                agruparDocumentosDia = value;

                if (agruparDocumentosDia)
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.DoWork += bw_DoWorkGroupDocumentsDay;
                    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
                    bw.RunWorkerAsync();
                }

                NotifyPropertyChanged(ObservableHelper.CreateArgs<InvoicesSummaryViewModel>(x => x.AgruparDocumentosDia));
            }
        }
        #endregion

        #region background workers
        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.ProcessingData = false;
        }

        void bw_DoWorkGroupLinesCode(object sender, DoWorkEventArgs e)
        {
            this.ProcessingData = true;

            InvoiceLines =
                (from l in allLines
                 group l by new { l.ItemElementName, l.ProductCode, l.Tax.Item } into c
                 select new LinhasAgrupadas { Tipo = c.Key.ItemElementName.ToString(), Produtos = c.Key.ProductCode, TaxaImposto = c.Key.Item, Incidencia = c.Sum(linha => linha.Item) }).ToArray();
        }

        void bw_DoWorkGroupLinesDescription(object sender, DoWorkEventArgs e)
        {
            this.ProcessingData = true;

            InvoiceLines =
                (from l in allLines
                 group l by new { l.ItemElementName, l.Description, l.Tax.Item } into c
                 select new LinhasAgrupadas { Tipo = c.Key.ItemElementName.ToString(), Produtos = c.Key.Description, TaxaImposto = c.Key.Item, Incidencia = c.Sum(linha => linha.Item) }).ToArray();
        }

        void bw_DoWorkGroupDocumentsDay(object sender, DoWorkEventArgs e)
        {
            this.ProcessingData = true;

            Invoices = (from d in allInvoices
                        group d by new { d.InvoiceType, d.InvoiceDate.Year, d.InvoiceDate.Month, d.InvoiceDate.Day } into g
                        select new DocumentosAgrupados
                        {
                            Tipo = g.Key.InvoiceType.ToString(),
                            Data = new DateTime(g.Key.Year, g.Key.Month, g.Key.Day),
                            Total = g.Sum(doc => doc.DocumentTotals.GrossTotal),
                            Incidencia = g.Sum(doc => doc.DocumentTotals.NetTotal),
                            Imposto = g.Sum(doc => doc.DocumentTotals.TaxPayable)
                        }).ToArray();
        }

        void bw_DoWorkGroupDocumentsMonth(object sender, DoWorkEventArgs e)
        {
            this.ProcessingData = true;

            Invoices = (from d in allInvoices
                        group d by new { d.InvoiceType, d.InvoiceDate.Year, d.InvoiceDate.Month } into g
                        select new DocumentosAgrupados
                        {
                            Tipo = g.Key.InvoiceType.ToString(),
                            Data = new DateTime(g.Key.Year, g.Key.Month, 1),
                            Total = g.Sum(doc => doc.DocumentTotals.GrossTotal),
                            Incidencia = g.Sum(doc => doc.DocumentTotals.NetTotal),
                            Imposto = g.Sum(doc => doc.DocumentTotals.TaxPayable)
                        }).ToArray();
        }
        #endregion

        #region Commands
        public SimpleCommand<object, object> DoExportDocumentsCommand { get; private set; }

        private void ExportDocuments(object args)
        {
            ExcelPackage pck = new ExcelPackage();
            var wsEnum = pck.Workbook.Worksheets.Add("SAFT Invoices");

            //Load the collection starting from cell A1...
            ExcelRangeBase dataRange = wsEnum.Cells["A1"].LoadFromCollection<DocumentosAgrupados>(Invoices, true, TableStyles.Medium9);

            wsEnum.Column(2).Style.Numberformat.Format = "yyyy/dd/mm";
            wsEnum.Column(3).Style.Numberformat.Format = "#,##0.00";
            wsEnum.Column(4).Style.Numberformat.Format = "#,##0.00";
            wsEnum.Column(5).Style.Numberformat.Format = "#,##0.00";
            dataRange.AutoFitColumns();

            var pivotTable2 = wsEnum.PivotTables.Add(wsEnum.Cells["G1"], dataRange, "Invoices");
            pivotTable2.RowFields.Add(pivotTable2.Fields["Tipo"]);

            //Add a rowfield
            var rowField = pivotTable2.RowFields.Add(pivotTable2.Fields["Data"]);
            //This is a date field so we want to group by Years and quaters. This will create one additional field for years.
            if (agruparDocumentosMes)
                rowField.AddDateGrouping(eDateGroupBy.Months);
            else if (AgruparDocumentosDia)
                rowField.AddDateGrouping(eDateGroupBy.Days);

            var dataField = pivotTable2.DataFields.Add(pivotTable2.Fields["Total"]);
            dataField.Format = "#,##0.00";
            dataField = pivotTable2.DataFields.Add(pivotTable2.Fields["Incidencia"]);
            dataField.Format = "#,##0.00";
            dataField = pivotTable2.DataFields.Add(pivotTable2.Fields["Imposto"]);
            dataField.Format = "#,##0.00";

            //We want the datafields to appear in columns
            pivotTable2.DataOnRows = false;

            //...and save
            var fi = new FileInfo(Path.GetTempPath() + Path.GetRandomFileName() + ".xlsx");

            pck.SaveAs(fi);

            Process.Start(fi.FullName);
        }

        private bool CanExportDocuments(object args)
        {
            return Invoices != null && Invoices.Length > 0;
        }

        public SimpleCommand<object, object> DoExportlinesCommand { get; private set; }

        private void ExportLines(object args)
        {
            ExcelPackage pck = new ExcelPackage();
            var wsEnum = pck.Workbook.Worksheets.Add("SAFT Invoice Lines");
            
            var dataRange = wsEnum.Cells["A1"].LoadFromCollection<LinhasAgrupadas>(InvoiceLines, true, TableStyles.Medium9);
            wsEnum.Cells[wsEnum.Dimension.Address].AutoFitColumns();
            wsEnum.Column(3).Style.Numberformat.Format = "#,##0.00";

            var pivotTable2 = wsEnum.PivotTables.Add(wsEnum.Cells["F1"], dataRange, "Invoice Lines");
            pivotTable2.RowFields.Add(pivotTable2.Fields["Tipo"]);

            var dataField = pivotTable2.DataFields.Add(pivotTable2.Fields["Incidencia"]);
            dataField.Format = "#,##0.00";

            //We want the datafields to appear in columns
            pivotTable2.DataOnRows = false;

            //...and save
            var fi = new FileInfo(Path.GetTempPath() + Path.GetRandomFileName() + ".xlsx");

            pck.SaveAs(fi);

            Process.Start(fi.FullName);
        }

        private bool CanExportLines(object args)
        {
            return InvoiceLines != null && InvoiceLines.Length > 0;
        }
        #endregion
    }
}
